home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / socket.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  10KB  |  362 lines

  1.  
  2. /*
  3.  * static char *rcsid_sockets_c =
  4.  *    "$Id: socket.c,v 1.28 1995/04/15 05:03:12 master Exp $";
  5.  */
  6.  
  7. /*
  8.     CrossFire, A Multiplayer game for X-windows
  9.  
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to frankj@ifi.uio.no.
  27. */
  28.  
  29. /*
  30.  * The routines in socket.c were mainly written by eanders+@cmu.edu
  31.  * I moved them to a separate file, since main() got too clobbered.  -Frank.
  32.  */
  33.  
  34.  
  35. #include <global.h>
  36. #ifndef __CEXTRACT__
  37. #include <sproto.h>
  38. #endif
  39. #ifdef SERVER
  40. #include <sys/types.h>
  41. #include <sys/time.h>
  42. #include <sys/socket.h>
  43. #include <netinet/in.h>
  44. #include <netdb.h>
  45. #if defined(hpux) || defined(SVR4)
  46. #include <unistd.h>
  47. #endif
  48. #if defined(_IBMR2) || defined(___IBMR2)
  49. #include <sys/select.h>
  50. #endif
  51. #if defined(__sun__) && !defined(SVR4)
  52. int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
  53. #endif
  54.  
  55.  
  56. int max_filedescriptors = 0;
  57. struct timeval timeout;
  58. int acceptfd,pollret;
  59. struct protoent *protox;
  60. struct sockaddr_in insock;
  61. struct sockaddr_in addr;
  62. int addrlen=sizeof(struct sockaddr);
  63. int doneone=0;
  64. unsigned short listen_port = PORT;
  65. #endif /* SERVER */
  66.  
  67. void init_socket() {
  68. #ifdef SERVER
  69.   if(server_mode == SERVER_ENABLED || debug)
  70.     LOG(llevError,"Opening add user socket on %d\n",listen_port);
  71.  
  72. #if defined(hpux) || defined (SVR4)
  73.   max_filedescriptors = sysconf(_SC_OPEN_MAX);
  74. #else
  75.   max_filedescriptors = getdtablesize();
  76. #endif
  77.   timeout.tv_sec = 0;
  78.   timeout.tv_usec = 0;
  79.  
  80.   protox = getprotobyname("tcp");
  81.  
  82.   if (protox==NULL) {
  83.     LOG(llevError,"Error getting protobyname\n");
  84.     exit(1);
  85.   }
  86.   acceptfd = socket(PF_INET,SOCK_STREAM,protox->p_proto);
  87.   if (acceptfd == (-1)) {
  88.     perror("error on socket command");
  89.     exit(-1);
  90.   }
  91.  
  92.   insock.sin_family = AF_INET;
  93.   insock.sin_port = htons(listen_port);
  94.   insock.sin_addr.s_addr = htonl(INADDR_ANY);
  95.  
  96.   {
  97.     struct linger linger_opt;
  98.     linger_opt.l_onoff = 0;
  99.     linger_opt.l_linger = 0;
  100.     if(setsockopt(acceptfd,SOL_SOCKET,SO_LINGER,(char *) &linger_opt,
  101.        sizeof(struct linger)))
  102.     perror("error on setsockopt LINGER");
  103.   }
  104.  
  105. #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
  106.     defined(__sun__) || defined(linux) || defined(SVR4)
  107.   {
  108.     char tmp =1;
  109.  
  110.     if(setsockopt(acceptfd,SOL_SOCKET,SO_REUSEADDR, &tmp, sizeof(&tmp)))
  111.       perror("error on setsockopt REUSEADDR");
  112.   }
  113. #else
  114.   if(setsockopt(acceptfd,SOL_SOCKET,SO_REUSEADDR,(char *)NULL,0))
  115.    perror("error on setsockopt REUSEADDR");
  116. #endif
  117.   if (bind(acceptfd,(struct sockaddr *)&insock,sizeof(insock)) == (-1)) {
  118.     if(server_mode == SERVER_ENABLED || debug)
  119.       perror("error on bind command");
  120.     abort_sockets();
  121.     return;
  122.   }
  123.  
  124.   if (listen(acceptfd,5) == (-1))  {
  125.     perror("error on listen");
  126.     abort_sockets();
  127.     return;
  128.   }
  129.  
  130.   if(server_mode == SERVER_ENABLED)
  131.     block_until_new_connection();
  132. #endif
  133. }
  134.  
  135. void check_socket() {
  136. #ifdef SERVER
  137.   fd_set tmp_read;
  138.   fd_set tmp_exceptions;
  139.   sockets *next=NULL;
  140.  
  141.   if(server_mode == SERVER_DISABLED)
  142.     return;
  143.  
  144.   FD_ZERO(&tmp_read);
  145.   FD_ZERO(&tmp_exceptions);
  146.   for(active_socket = first_socket; active_socket != (sockets *) NULL;
  147.       active_socket = active_socket->next) {
  148.     FD_SET(active_socket->fd,&tmp_read);
  149.     FD_SET(active_socket->fd,&tmp_exceptions);
  150.   }
  151.   FD_SET(acceptfd,&tmp_read);
  152.  
  153.   pollret = select(max_filedescriptors,&tmp_read,NULL,&tmp_exceptions,&timeout);
  154.   if (pollret == (-1)) {
  155.     perror("select");
  156.     return;
  157.   }
  158.   if (!pollret)    /* Nothing new */
  159.     return;
  160.   if (FD_ISSET(acceptfd,&tmp_read)) { /* try to accept any new connections */
  161.     int fd = accept(acceptfd,(struct sockaddr *)&addr,&addrlen);
  162.     if (fd == (-1))
  163.       perror("accept");
  164.     else {
  165.       unsigned long from = ntohl(addr.sin_addr.s_addr);
  166.       add_socket(fd, from);
  167.     }
  168.   }
  169.   for(active_socket = first_socket; active_socket != (sockets *) NULL;
  170.       active_socket = next) {
  171.     next = active_socket->next;
  172.     if(FD_ISSET(active_socket->fd,&tmp_exceptions)) {
  173.       LOG(llevError,"Exception received at %d\n",active_socket->fd);
  174.       remove_socket(active_socket);
  175.       continue;
  176.     }
  177.     if(FD_ISSET(active_socket->fd,&tmp_read)) {
  178.       int readct;
  179.       char buf[SOCKET_BUFLEN+1];
  180.       /* Have input */
  181.       readct = read(active_socket->fd,buf,SOCKET_BUFLEN);
  182.       if(readct == (-1)) {
  183.         perror("read");
  184.         continue;
  185.       }
  186.       if (readct==0) {
  187.         close(active_socket->fd);
  188.         remove_socket(active_socket);
  189.         if (server_mode == SERVER_ABORTED) {
  190.           LOG(llevError, "Server mode ended.\n");
  191.           server_mode = SERVER_OFF;
  192.         }
  193.       } else {
  194.     /* The following should never ever happen. */
  195.         if (readct>SOCKET_BUFLEN) {
  196.           if(debug)
  197.             LOG(llevError,"Error, Protocol Violation, input too long\n");
  198.           draw_socket(active_socket->fd,"Line too long, ignored.");
  199.  
  200.       /* Having this be fatal probably does not make much
  201.        * difference - if the buffer was overflowed, various
  202.        * areas of data will be corrupted in any case.
  203.        */
  204.           /*return; *//* Why should this be fatal??? */
  205.       continue;
  206.     }
  207.         buf[readct]='\0';
  208.         if (buf[readct-1] == '\n')
  209.           buf[--readct] = '\0';
  210.         if (buf[readct-1] == '\r')
  211.           buf[--readct] = '\0';
  212.         if (debug) /* Would get useless echos if I used LOG() here */
  213.           if (strncmp(buf, "dm ", 3)) /* Better not log the password */
  214.             fprintf(logfile,"socket[%s]: %s\n",active_socket->name,buf);
  215.         if(buf[0]=='\0')
  216.           continue; /* Empty line */
  217.  
  218.         parse_string(NULL,buf);
  219.         if (active_socket->quit == 1)
  220.         {
  221.           close(active_socket->fd);
  222.           remove_socket(active_socket);
  223.         }
  224.       }
  225.     }
  226.   }
  227.   active_socket = (sockets *) NULL;
  228. #endif /* SERVER */
  229. }
  230.  
  231. void add_socket(int fd, unsigned long from) {
  232. #ifdef SERVER
  233.   sockets *socket = (sockets *) malloc(sizeof(sockets));
  234.   socket->fd = fd;
  235.   sprintf(socket->host,"%ld.%ld.%ld.%ld",
  236.           (from>>24)&255, (from>>16)&255, (from>>8)&255, from&255);
  237.   LOG(llevDebug, "Adding socket %d from %s.\n",fd,socket->host);
  238.   socket->listen_lev = 8;
  239.   socket->wiz = 0;
  240.   socket->use_pix = 0;
  241.   socket->color_pix = 0;
  242.   socket->split = 0;
  243.   socket->debug = llevError;
  244.   socket->protocol = 0;
  245.   socket->quit = 0;
  246.   socket->next = first_socket;
  247.   first_socket = socket;
  248.   if(fd>9999 || fd < 0)
  249.     strcpy(socket->name,"anonym");
  250.   else
  251.     sprintf(socket->name,"anon%d",fd);
  252.   draw_socket(socket->fd, "Welcome to a crossfire server.  Type 'help' if you need help.");
  253. #endif
  254. }
  255.  
  256. void set_protocol(sockets *s, int p) {
  257.   if (p < 0 || p > 1) {
  258.     char buf[MAX_BUF];
  259.     sprintf(buf,"Invalid protocol, accepted protocols are: 0 1");
  260.     draw_socket(s->fd, buf);
  261.   }
  262.   s->protocol = p;
  263.   draw_socket(s->fd, "OK.");
  264. }
  265.  
  266. void remove_socket(sockets *socket) {
  267. #ifdef SERVER
  268.   sockets *tmp, *prev = NULL;
  269.  
  270.   for(tmp = first_socket; tmp != NULL; prev = tmp, tmp = tmp->next)
  271.     if(tmp == socket)
  272.       break;
  273.   if(tmp == NULL) {
  274.     LOG(llevError,"remove_socket: no such socket\n");
  275.     return;
  276.   }
  277.   if(prev == NULL)
  278.     first_socket = tmp->next;
  279.   else
  280.     prev->next = tmp->next;
  281.   LOG(llevDebug,"Removing socket %d\n",tmp->fd);
  282.   free(tmp);
  283.   if (first_player == (player *) NULL &&
  284.       first_socket == (sockets *) NULL && server_mode == SERVER_ENABLED)
  285.     block_until_new_connection();
  286. #endif
  287. }
  288.  
  289. void close_all_sockets() {
  290. #ifdef SERVER
  291.   info_all_sockets("Crossfire died, disconnecting...");
  292.   server_mode = SERVER_ABORTED; /* Don't want to block */
  293.   while(first_socket != (sockets *) NULL) {
  294.     close(first_socket->fd);
  295.     remove_socket(first_socket);
  296.   }
  297. #endif
  298. }
  299.  
  300. void draw_socket(int fd, const char *str) {
  301. #ifdef SERVER
  302.   int i=0,len;
  303.   char *buf = (char *) malloc(sizeof(char) * strlen(str) + 2);
  304.  
  305.   strcpy(buf,str);
  306.   strcat(buf,"\n");
  307.   str = buf;
  308.  
  309.   while ((len = strlen(str))) {
  310.     i=write(fd,str,len);
  311.     if(i < 0) {
  312.       perror("draw_socket");
  313.       break;
  314.     }
  315.     else if (i != len) {
  316.       LOG(llevDebug, "draw_socket: write returned %d of %d\n", i, len);
  317.     } else
  318.       str+=i;
  319.   }
  320.   free(buf);
  321. #endif
  322. }
  323.  
  324. void info_all_sockets(char *txt) {
  325. #if defined(SERVER)
  326.   sockets *s;
  327.   for(s = first_socket; s != (sockets *) NULL; s = s->next)
  328.     if (s->protocol != 1 && s->listen_lev>0)
  329.       draw_socket(s->fd,txt);
  330. #endif
  331. }
  332.  
  333. void abort_sockets() {
  334. #ifdef SERVER
  335.   if(server_mode != SERVER_ENABLED) {
  336.     LOG(llevDebug,"Turning off sockets.\n");
  337.     if(close(acceptfd))
  338.       perror("Disabling sockets/close");
  339.     server_mode = SERVER_DISABLED; /* No need to check them in the future */
  340.     return;
  341.   }
  342.   exit(1);
  343. #endif
  344. }
  345.  
  346. void block_until_new_connection()
  347. {
  348. #ifdef SERVER
  349.   fd_set readfs;
  350.  
  351.   FD_ZERO(&readfs);
  352.   FD_SET(acceptfd, &readfs);
  353. #if ERIC_SERVER
  354.   FD_SET(ericfd(),&readfs);
  355. #endif
  356.  
  357.   LOG(llevError, "Waiting for connections...\n");
  358.   (void) select(max_filedescriptors, &readfs, NULL, NULL, NULL);
  359.   reset_sleep(); /* Or the game would go too fast */
  360. #endif
  361. }
  362.